package com.lyl.activiti.demo.web.controller;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by liyulong on 14-3-26.
 */

@Controller
@RequestMapping(value = "/task")
public class TaskController extends BaseController {

    private static final String EXTERNAL_FORM_PROCESS_DEFINITION_KEY = "leaveProcess";

    /**
     * 流程列表
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/processList")
    public String processList(Model model) {
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //获取最新版本的流程定义
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey(EXTERNAL_FORM_PROCESS_DEFINITION_KEY).latestVersion().orderByProcessDefinitionId().asc().list();

        model.addAttribute("processList", processDefinitionList);
        return "/task/processList";
    }

    /**
     * 开始流程
     *
     * @param processKey
     * @param model
     * @param session
     * @return
     */
    @RequestMapping(value = "/startProcess")
    public String startProcess(String processKey, Model model, HttpSession session) {
        String userId = ((User) session.getAttribute("user")).getId();
        // 启动用户信息
        identityService.setAuthenticatedUserId(userId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey);
        return "/task/processList";
    }

    /**
     * 获取任务的开始表单
     *
     * @param processDefinitionId
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/getProcessStartForm/{processDefinitionId}")
    @ResponseBody
    public Object getProcessStartForm(@PathVariable("processDefinitionId") String processDefinitionId) throws Exception {
        // 根据流程定义ID读取外置表单
        Object startForm = formService.getRenderedStartForm(processDefinitionId);
        return startForm;
    }

    /**
     * 读取启动流程的表单字段
     */
    @RequestMapping(value = "/startProcessWithForm/{processDefinitionId}")
    public String startProcessWithForm(@PathVariable("processDefinitionId") String processDefinitionId, Model model, HttpSession session, HttpServletRequest request) {
        String userId = ((User) session.getAttribute("user")).getId();
        Map<String, String> formProperties = new HashMap<String, String>();

        // 从request中读取表单参数然后转换(就是去掉页面中name的前缀fp_)
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entrySet = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entrySet) {
            String key = entry.getKey();
            // fp_的意思是form paremeter
            if (StringUtils.defaultString(key).startsWith("fp_")) {
                formProperties.put(key.split("_")[1], entry.getValue()[0]);
            }
        }
        try {
            identityService.setAuthenticatedUserId(userId);
            ProcessInstance processInstance = formService.submitStartFormData(processDefinitionId, formProperties);
            model.addAttribute("message", processInstance.getId());
        } finally {
            identityService.setAuthenticatedUserId(null);
        }

        return "redirect:/task/processList";
    }

    /**
     * 获取当前任务的表单
     *
     * @param taskId
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/getTaskForm/{taskId}")
    @ResponseBody
    public Object getTaskForm(@PathVariable("taskId") String taskId) throws Exception {
        Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
        return renderedTaskForm;
    }

    /**
     * 完成当前任务
     *
     * @param taskId
     * @param redirectAttributes
     * @param request
     * @return
     */
    @RequestMapping(value = "/completeTask/{taskId}")
    public String completeTask(@PathVariable("taskId") String taskId, RedirectAttributes redirectAttributes, HttpServletRequest request, HttpSession session) {
        String userId = ((User) session.getAttribute("user")).getId();
        Map<String, String> formProperties = new HashMap<String, String>();

        // 从request中读取参数然后转换
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entrySet = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entrySet) {
            String key = entry.getKey();
            if (StringUtils.defaultString(key).startsWith("fp_")) {
                String[] paramSplit = key.split("_");
                formProperties.put(paramSplit[1], entry.getValue()[0]);
            }
        }

        try {
            identityService.setAuthenticatedUserId(userId);
            formService.submitTaskFormData(taskId, formProperties);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }

        redirectAttributes.addFlashAttribute("message", "任务完成：taskId=" + taskId);
        return "redirect:/task/processList";
    }


    /**
     * 待办任务列表
     *
     * @param model
     * @param session
     * @return
     */
    @RequestMapping(value = "/toDoProcessList")
    public String userToDoProcessList(Model model, HttpSession session) {
        String userId = ((User) session.getAttribute("user")).getId();
        //获取当前用户为候选人的任务
        List<Task> tasks = taskService.createTaskQuery().processDefinitionKey(EXTERNAL_FORM_PROCESS_DEFINITION_KEY).taskCandidateUser(userId).list();
        //获取已经分配给当前用户的任务
        List<Task> tasks1 = taskService.createTaskQuery().taskAssignee(userId).list();
        tasks.addAll(tasks1);
        model.addAttribute("tasks", tasks);
        return "/task/toDoProcessList";
    }

    /**
     * 签收流程
     *
     * @param processInstanceId
     * @param model
     * @param session
     * @return
     */
    @RequestMapping(value = "/claimProcess")
    public String claimProcess(String processInstanceId, Model model, HttpSession session) {
        String userId = ((User) session.getAttribute("user")).getId();
        taskService.claim(processInstanceId, userId);
        return "redirect:/task/toDoProcessList";
    }

    /**
     * 运行中流程
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/runningProcessList")
    public String runningProcess(Model model, HttpSession session) {
        String userId = ((User) session.getAttribute("user")).getId();
        List<ProcessInstance> runningProcessList = runtimeService.createProcessInstanceQuery().processDefinitionKey(EXTERNAL_FORM_PROCESS_DEFINITION_KEY).involvedUser(userId).active().list();
        model.addAttribute("runningProcessList", runningProcessList);
        return "/task/runningProcessList";
    }

    /**
     * 已完成的流程实例
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/finishedProcessList")
    public String finished(Model model, HttpServletRequest request, HttpSession session) {
        String userId = ((User) session.getAttribute("user")).getId();
        List<HistoricProcessInstance> finishedProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey(EXTERNAL_FORM_PROCESS_DEFINITION_KEY).startedBy(userId).orderByProcessInstanceEndTime().desc().finished().list();
        model.addAttribute("finishedProcessList", finishedProcessList);
        return "/task/finishedProcessList";
    }

    /**
     * 获取当前流程实例的流程图
     *
     * @param processInstanceId
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/image/{processInstanceId}")
    public void getImage(@PathVariable("processInstanceId") String processInstanceId, HttpServletResponse response) throws IOException {
        // 获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        // 根据流程定义获得模型定义
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        // 此方法用于强制读取配置文件中的字体
        Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
        // 利用ProcessDiagramGenerator生成当前激活任务的图片流
        InputStream definitionImageStream = ProcessDiagramGenerator.generateDiagram(bpmnModel, "png", runtimeService.getActiveActivityIds(processInstanceId));
        // 输出资源内容到相应对象
        byte[] b = new byte[1024];
        int len;
        while ((len = definitionImageStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 获取流程定义图
     *
     * @param processDefinitionId
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/processDefinitionImage/{processDefinitionId}")
    public void getProcessDefinitionImage(@PathVariable("processDefinitionId") String processDefinitionId, HttpServletResponse response) throws Exception {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

}
